package deployr.core;

import static deployr.core.Checksums.*;

import java.io.*;
import java.util.*;

public class WebAppBuilder implements ScanListener {
	private final Map<String, String> index = new TreeMap<String, String>();

	private final Map<String, String> added = new TreeMap<String, String>();

	private final Map<String, String> updated = new TreeMap<String, String>();

	private final Collection<String> removed = new LinkedList<String>();

	private File currRoot;

	private StringBuilder currchecksum = new StringBuilder();

	private StringBuilder prevchecksum = new StringBuilder();

	private ChecksumBuilder checksum = new ChecksumBuilder(usingSha1());

	public WebAppBuilder() {}

	private String checksum(String root, String file) {
		return checksum.checksum(new File(root, file));
	}

	public WebAppBuilder curr(String currchecksum) {
		this.currchecksum.append(currchecksum).append("\n");
		return this;
	}

	public WebAppBuilder currRoot(Path path) {
		this.currRoot = path.getAbsoluteFile();
		return this;
	}

	public void discovered(File root, File file) {
		String rootPath = root.getAbsolutePath();
		String filePath = file.getAbsolutePath().replaceAll("^/", "");
		String checksum = checksum(rootPath, filePath);
		if (unchanged(filePath, checksum)) {
			index.remove(filePath);
			added.remove(filePath);
			return;
		}
		discoveredUpdate(filePath, checksum);
		discoveredNew(filePath, checksum);
	}

	public void discovered(String path, String md5) {
		discoveredUpdate(path, md5);
		discoveredNew(path, md5);
	}

	private void discoveredNew(String path, String md5) {
		if (!index.containsKey(path)) {
			added.put(path, md5);
			index.put(path, md5);
		}
	}

	private void discoveredUpdate(String path, String md5) {
		if (index.containsKey(path) && !index.get(path).equals(md5)) {
			added.remove(path);
			updated.put(path, md5);
		}
	}

	private boolean exist(File root) {
		return root != null && root.exists();
	}

	private boolean exist(StringBuilder checksum) {
		return checksum != null && checksum.length() > 0;
	}

	public WebApp newWebApp() {
		if (exist(currchecksum)) scan(currchecksum);
		if (exist(prevchecksum)) scan(prevchecksum);
		if (exist(currchecksum) && exist(prevchecksum)) scanRemoved(currchecksum, prevchecksum);
		if (exist(currRoot)) scan(currRoot);
		return new WebApp(root(), added, updated, removed);
	}

	public WebAppBuilder prev(String prevchecksum) {
		this.prevchecksum.append(prevchecksum).append("\n");
		return this;
	}

	public void remove(String string) {
		removed.add(string);
	}

	private String root() {
		if (currRoot == null) return "";
		return currRoot.getAbsolutePath();
	}

	private void scan(File root) {
		new Scan(this, root);
	}

	private void scan(StringBuilder checksum) {
		new ScanChecksum(this, checksum.toString());
	}

	private void scanRemoved(StringBuilder currchecksum, StringBuilder prevchecksum) {
		new ScanRemovedChecksum(this, currchecksum.toString(), prevchecksum.toString());
	}

	private boolean unchanged(String path, String md5) {
		return index.containsKey(path) && index.get(path).equals(md5);
	}

	public WebAppBuilder add(Checksum checksum) {
		for(String path: checksum) {
			discovered(path, checksum.hash(path));
		}
		return this;
	}

	public WebApp newWebApp(File root) {
		return new WebApp(root.getAbsolutePath(), added, updated, removed);
	}

}